<template>
    <div>
        <h3>三维旋转</h3>
        <div ref="myCanvas" class="myCanvas"></div>
        <h3>机器人跳舞</h3>
        <div ref="tiaowuCanvas" class="myCanvas"></div>
    </div>
</template>

<script setup lang="ts">
// 引入three
import * as THREE from 'three';
// WebGL兼容性检查文件引入
import WebGL from 'three/addons/capabilities/WebGL.js';
//引入文本缓冲几何体（TextGeometry）
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
// 引入一个用于加载JSON格式的字体的类
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
// 引入机器人跳舞相关
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import Stats from 'three/addons/libs/stats.module.js';
//

// import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// 定义myCanvas的ref
const myCanvas = ref();
// ================文字立方体开始=================
// 建立了场景
let scene: any = null;
// 建立摄像机  
let camera: any = null;
// 建立渲染器
let renderer: any = null;
// 要创建一个立方体。
let geometry: any = null;
// 接下来，对于这个立方体。
let material: any = null;
// 第三步，我们需要一个 Mesh（网格）。
let cube: any = null;

//定义加载字体的loader
let loader: any = null;
//定义字体对象函数
let geometryFont: any = null;
// 设置光源
let ambientLight: any = null;
// 创建文字材质
let materials: any = null;
// 创建文字几何体材质
let textMesh1: any = null;
/**
 * 初始化three
 */
const myThree = () => {
    // 建立了场景
    scene = new THREE.Scene();
    // 建立摄像机  第一个参数是视野角度（FOV） 第二个参数是长宽比（aspect ratio） 接下来的两个参数是近截面（near）和远截面（far）
    camera = new THREE.PerspectiveCamera(75, myCanvas.value.clientWidth / myCanvas.value.clientHeight, 0.1, 1000);
    // 建立渲染器
    renderer = new THREE.WebGLRenderer();

    // 设置一个渲染器的尺寸
    renderer.setSize(myCanvas.value.clientWidth, myCanvas.value.clientHeight);

    myCanvas.value.appendChild(renderer.domElement);
    myGeometry();

    camera.position.z = 5;
    myThreeFont();
    setTimeout(() => {
        animate()
    }, 100);

}
const myGeometry = () => {
    // 要创建一个立方体，我们需要一个 BoxGeometry（立方体）对象. 这个对象包含了一个立方体中所有的顶点（vertices）和面（faces）。
    geometry = new THREE.BoxGeometry(1, 1, 1);
    // 接下来，对于这个立方体，我们需要给它一个材质，来让它有颜色。
    material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });

    // 第三步，我们需要一个 Mesh（网格）。 网格包含一个几何体以及作用在此几何体上的材质，我们可以直接将网格对象放入到我们的场景中，并让它在场景中自由移动。
    cube = new THREE.Mesh(geometry, material);
    // 默认情况下，当我们调用 scene.add() 的时候，物体将会被添加到 (0,0,0) 坐标。但将使得摄像机和立方体彼此在一起。为了防止这种情况的发生，我们只需要将摄像机稍微向外移动一些即可。
    scene.add(cube);
}
/**
 * 注意：
 * 创建文字
 */
const myThreeFont = () => {
    loader = new FontLoader();

    loader.load('../../../node_modules/three/examples/fonts/helvetiker_regular.typeface.json', function (font: any) {
        geometryFont = new TextGeometry('Hello three.js!', {
            font: font,
            size: 1, // Float。字体大小，默认值为100。
            height: 1, //  Float。挤出文本的厚度。默认值为50。
            curveSegments: 12, // Integer （表示文本的）曲线上点的数量。默认值为12。
            bevelEnabled: true, // Boolean 是否开启斜角，默认为false。
            bevelThickness: 0.01, // Float。文本上斜角的深度，默认值为20。
            bevelSize: 0.02,// Float。斜角与原始文本轮廓之间的延伸距离。默认值为8。
            bevelSegments: 3 // Integer 斜角的分段数。默认值为3。

        });
        // 建立文字材质
        materials = [
            new THREE.MeshPhongMaterial({
                color: 0xffffff,
                flatShading: true,
                shininess: 100
            }),//front
            new THREE.MeshPhongMaterial({
                color: 0xff0000, flatShading: true,
                shininess: 100
            })//back
        ]
        console.log(materials);

        // 几何体材质
        textMesh1 = new THREE.Mesh(geometryFont, materials)
        textMesh1.position.set(0, 0, 0)
        // 建立一个光源
        ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
        scene.add(ambientLight);
        scene.add(textMesh1)

    });
}
// ================文字立方体结束=================
// 建立了场景
let tiaowuScene: any = null;
// 建立摄像机  
let tiaowuCamera: any = null;
// 建立渲染器
let tiaowuRenderer: any = null;

let tiaowuMixer: any = null;


let tiaowuStats: any = null;

let tiaowuClock: any = null;

let tiaowuControls: any = null;
// 定义了机器人跳舞的ref
const tiaowuCanvas = ref();
const tiaowuInit = () => {

    tiaowuCamera = new THREE.PerspectiveCamera(25, tiaowuCanvas.value.clientWidth / tiaowuCanvas.value.clientHeight, 1, 1000);
    tiaowuCamera.position.set(15, 5, - 15);
    tiaowuScene = new THREE.Scene();
    tiaowuClock = new THREE.Clock();
    // collada

    const tiaowuLoader = new GLTFLoader();
    tiaowuLoader.load('../../../public/three/dancing_stormtrooper/scene.gltf', function (collada: any) {
        // 建立一个网格模型
        const avatar = collada.scene;
        // 模型y轴90度
        avatar.rotation.set(0, 90, 0);
        const animations = collada.animations;
        tiaowuMixer = new THREE.AnimationMixer(avatar);
        tiaowuMixer.clipAction(animations[0]).play();
        tiaowuScene.add(avatar);
    }
    );
    //

    const gridHelper = new THREE.GridHelper(10, 20, 0xc1c1c1, 0x8d8d8d);
    tiaowuScene.add(gridHelper);

    //

    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
    tiaowuScene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 3);
    directionalLight.position.set(1.5, 1, - 1.5);
    tiaowuScene.add(directionalLight);

    //

    tiaowuRenderer = new THREE.WebGLRenderer({ antialias: true });
    tiaowuRenderer.setPixelRatio(window.devicePixelRatio);
    tiaowuRenderer.setSize(tiaowuCanvas.value.clientWidth, tiaowuCanvas.value.clientHeight);
    tiaowuCanvas.value.appendChild(tiaowuRenderer.domElement);

    //

    tiaowuControls = new OrbitControls(tiaowuCamera, tiaowuRenderer.domElement);
    tiaowuControls.screenSpacePanning = true;
    tiaowuControls.minDistance = 5;
    tiaowuControls.maxDistance = 40;
    tiaowuControls.target.set(0, 2, 0);
    tiaowuControls.update();

    //

    tiaowuStats = new Stats();

    tiaowuCanvas.value.appendChild(tiaowuStats.dom);

    //

    window.addEventListener('resize', onWindowResize);
    setTimeout(() => {
        tiaowuAnimate()
    }, 500);

}

const onWindowResize = () => {

    tiaowuCamera.aspect = tiaowuCanvas.value.clientWidth / tiaowuCanvas.value.clientHeight;
    tiaowuCamera.updateProjectionMatrix();

    tiaowuRenderer.setSize(tiaowuCanvas.value.clientWidth, tiaowuCanvas.value.clientHeight);

}

const tiaowuAnimate = () => {

    requestAnimationFrame(tiaowuAnimate);

    tiaowuRender();
    tiaowuStats.update();

}

const tiaowuRender = () => {

    const delta = tiaowuClock.getDelta();

    if (tiaowuMixer !== undefined) {

        tiaowuMixer.update(delta);

    }

    tiaowuRenderer.render(tiaowuScene, tiaowuCamera);

}
// 动画渲染
const animate = () => {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    textMesh1.rotation.x += 0.01;
    textMesh1.rotation.y += 0.01;


    renderer.render(scene, camera);
}
/**
 * 注意：
 * WebGL兼容性检查
 */
const myWebGL = () => {
    if (WebGL.isWebGLAvailable()) {
        myThree()
    } else {
        const warning = WebGL.getWebGLErrorMessage();
        myCanvas.value.appendChild(warning);
    }
}
onMounted(() => {
    myWebGL()
    tiaowuInit();
})
</script>

<style scoped lang="less">
h3 {
    text-align: center;
}

.myCanvas {
    width: 100%;
    height: 600px;
}
</style>